<?php
declare(strict_types=1);

/**
 * Created by PhpStorm.
 * User: 小灰灰
 * Date: 2021-05-25
 * Time: 上午10:27:11
 * Info: 后台操作日志中间件
 */

namespace app\admin\middleware;

use app\common\model\AuthRule as AuthRuleModel;
use app\common\model\SystemLog as SystemLogModel;
use think\Request;

class SystemLog
{

    /**
     * 敏感信息字段，日志记录时需要加密
     * @var array
     */
    protected array $sensitiveParams = [
        'password',
        'password_again',
    ];

    /**
     * 处理系统日志记录
     *
     * @param Request  $request
     * @param \Closure $next
     *
     * @return mixed
     */
    public function handle(Request $request, \Closure $next)
    {
        // 自动延长会话时间
        $this->extendSessionTime();

        // 只处理 AJAX 请求
        if ($request->isAjax()) {
            $method = strtolower($request->method());

            // 只记录写操作日志
            if (in_array($method, ['post', 'put', 'delete'], true)) {
                $this->recordOperationLog($request, $method);
            }
        }

        return $next($request);
    }

    /**
     * 延长会话时间
     */
    private function extendSessionTime(): void
    {
        $adminId = cmf_get_admin_id();
        if ( ! $adminId) {
            return;
        }

        $currentUserInfo = cmf_get_current_admin_info();
        $expireTime      = null;
        if ($currentUserInfo && isset($currentUserInfo['expire_time'])) {
            $expireTime = $currentUserInfo['expire_time'];
        }

        if ($expireTime && $expireTime !== true && time() - $expireTime < 300) {
            // 更新当前用户的过期时间
            $adminUsers = session('admin_users') ?: [];
            if (isset($adminUsers[$adminId])) {
                $adminUsers[$adminId]['expire_time'] = $expireTime + 7200; // 2小时
                session('admin_users', $adminUsers);
            }
        }
    }

    /**
     * 记录操作日志
     *
     * @param Request $request
     * @param string  $method
     */
    private function recordOperationLog(Request $request, string $method): void
    {
        // 获取后台配置：是否开启后台操作日志
        $operationLogAdmin = get_config('operation_log_admin');
        if ( ! $operationLogAdmin) {
            return;
        }

        $url    = $request->pathinfo();
        $ext    = $request->ext();
        $ip     = get_client_ip();
        $params = $this->getInputData();

        // 移除路由参数
        if (isset($params['s'])) {
            unset($params['s']);
        }

        // 处理敏感信息
        $this->processSensitiveParams($params);

        // 获取节点标题
        $node  = explode('.'.$ext, $url)[0];
        $title = AuthRuleModel::where('node', $node)->value('title') ?? '';

        // 构造日志数据
        $data = [
            'admin_id'    => cmf_get_admin_id(),
            'url'         => $url,
            'title'       => $title,
            'method'      => $method,
            'ip'          => $ip,
            'content'     => json_encode($params, JSON_UNESCAPED_UNICODE),
            'useragent'   => $request->server('HTTP_USER_AGENT', ''),
            'create_time' => time(),
        ];

        SystemLogModel::addData($data);
    }

    /**
     * 获取请求输入数据
     *
     * @return array
     */
    private function getInputData(): array
    {
        $input = file_get_contents('php://input');

        if (empty($input)) {
            return [];
        }

        if (strpos($input, '=')) {
            parse_str($input, $data);

            return $data;
        }

        $jsonData = json_decode($input, true);

        return is_array($jsonData) ? $jsonData : [];
    }

    /**
     * 处理敏感参数
     *
     * @param array $params
     */
    private function processSensitiveParams(array &$params): void
    {
        if (empty($params)) {
            return;
        }

        foreach ($params as $key => $val) {
            if (in_array($key, $this->sensitiveParams, true)) {
                $params[$key] = md5(md5((string)$val));
            }
        }
    }
}
